Keyboard-select composer controls with hold-modifier hints - #4271
Keyboard-select composer controls with hold-modifier hints#4271colonelpanic8 wants to merge 17 commits into
Conversation
|
Important Review skippedAuto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
ApprovabilityVerdict: Needs human review This PR introduces a new keyboard shortcut feature for composer and toolbar controls, with visual hint badges appearing when modifier keys are held. New user-facing features with new components, new hooks, and new state management patterns warrant human review. You can customize Macroscope's approvability policy. Learn more. |
Adds pingdotgg/t3code#4271 (keyboard-select composer controls + hold-modifier hints) as the final entry in the applyPatches stack. The raw cumulative diff applies with fuzz after #4258 and #4260, so it uses a plain fetchurl GitHub link rather than a local compatibility patch. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Bump the pingdotgg/t3code#4271 fetchurl hash to the current PR head (51135b2cc), pulling in the Cursor/Macroscope review fixes (terminal-focus aware hints, layout-scoped picker open state, mutually-exclusive toolbar pickers, branch-search reset). Raw cumulative diff still applies with fuzz. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
51135b2 to
dd6cfa5
Compare
5c9615f to
a371312
Compare
8ebc09a to
c2702bb
Compare
d0c50d2 to
3a03660
Compare
d5ca73b to
0c612c0
Compare
6e28fd6 to
c5ab798
Compare
78cebd1 to
50f5812
Compare
…-modifier hints) # Conflicts: # apps/web/src/components/BranchToolbarBranchSelector.tsx
…-modifier hints) # Conflicts: # apps/web/src/components/BranchToolbarBranchSelector.tsx # apps/web/src/components/chat/ProviderModelPicker.tsx
…-modifier hints) # Conflicts: # apps/web/src/components/BranchToolbarBranchSelector.tsx # apps/web/src/components/chat/ProviderModelPicker.tsx
…-modifier hints) # Conflicts: # apps/web/src/components/BranchToolbarBranchSelector.tsx # apps/web/src/components/chat/ProviderModelPicker.tsx
…-modifier hints) # Conflicts: # apps/web/src/components/BranchToolbarBranchSelector.tsx # apps/web/src/components/chat/ProviderModelPicker.tsx
08e2bb9 to
6c949cf
Compare
Make every selector in the thread first-prompt composer keyboard-operable through the existing customizable keybindings system, alongside the pre-existing modelPicker.toggle command: - modelOptionsPicker.toggle (mod+shift+e): reasoning effort / traits menu - runtimeModePicker.toggle (mod+shift+a): access level select - planMode.toggle (mod+shift+p): Plan/Build toggle - environmentPicker.toggle (mod+shift+v): branch toolbar environment - envModePicker.toggle (mod+shift+l): local vs worktree - branchPicker.toggle (mod+shift+b): branch selector All six are rebindable in Settings -> Keybindings (labels derived by the existing commandLabel helper) and are upserted into existing configs by the server's startup sync. Holding the platform mod key reveals Kbd hint badges on each control via shouldShowComposerControlHintsForModifiers, which uses subset (not exact) modifier matching so a bare Ctrl/Cmd reveals the chords. Compact footer routes the effort/runtime toggles to CompactComposerControlsMenu; mobile routes environment/env-mode to the combined run-context menu. Toggles report availability so unavailable controls leave the browser default intact. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The hold-modifier hint chips were rendered inline inside the composer control triggers, crowding out the current values (the model name truncated to almost nothing). Render them instead as detached, portaled tooltips anchored below each trigger, so the model, options, approval and runtime-mode values stay fully visible while hints are shown. The branch toolbar keeps its inline hints since those labels have room. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
6c949cf to
5dce024
Compare
The hold-modifier hints were detached tooltips anchored below their triggers, so they landed on the branch toolbar row underneath and collided with the inline badges already rendered there. Render the keycap in layout instead, taking over the disclosure chevron's slot: a cap and a chevron are within a few pixels of each other, so the row barely moves, the current values stay readable, and the composer and toolbar rows finally use one treatment. Labels now drop the platform mod key — Ctrl on Linux/Windows, Cmd on macOS — which the user must already be holding for a hint to be visible at all. `mod+shift+e` reads `Shift+E`. Subtraction is per binding rather than a shared-prefix assumption, so a chord rebound to `mod+alt+e` renders `Alt+E` beside its neighbours, and the label does not reflow as further modifiers go down. Also: - `envModePicker.toggle` flips local <-> worktree directly instead of opening a two-item menu, matching `planMode.toggle`. Clicking still opens the menu, which is what surfaces the worktree path. - The environment and workspace indicators explain themselves while inert, distinguishing a thread that has already started from a project with only one environment. They previously rendered as muted, chevron-less controls that silently did nothing.
Shortcut labels spelled modifiers out on Linux and Windows (`Ctrl+Shift+E`) while already using Apple's glyphs on macOS. Use one representation everywhere: `⌃⌥⇧` for control, option and shift on every platform, `⌘` for command on macOS, in Apple's canonical order with no separators. Non-letter keys get their glyphs too, so `mod+backspace` is `⌃⌫` rather than `⌃Backspace`. Keys with no established glyph — function keys, punctuation — keep their word. A non-mac meta/super key has no Apple glyph, so it stays `Super` rather than borrowing `⌘`, which would be a lie about which key to press. This matters most for the hold-modifier keycaps, where `⌃⇧E` fits a control's chevron slot and `Ctrl+Shift+E` does not, but the same representation now applies to the command palette, sidebar chips, terminal tooltips, and the keybindings settings table. That table rendered each token as its own chip via a separate platform conditional, which had already drifted (`Ctrl` beside `⇧`); it now shares the one token formatter.
…old-modifier hints) # Conflicts: # apps/web/src/keybindings.test.ts
…old-modifier hints) # Conflicts: # apps/web/src/keybindings.test.ts
The caps dropped the platform mod key on the grounds that the user was already holding it. That reasoning was sound when a cap read `Shift+E` and every pixel counted, but the Apple glyphs shrank the full chord to `⌃⇧E` — about 8px wider than `⇧E` — so the saving no longer pays for making the reader reconstruct which modifier the hint belongs to. Showing the whole chord also matches how macOS menus print shortcuts, and it removes a function: the per-command gate already decides whether a hint is visible, so the label is now just `shortcutLabelForCommand`.
|
Superseded by #4701, which carries the Apple-glyph shortcut labels on their own against The composer hold-modifier hint work from this branch (keycaps in the disclosure-chevron slot, direct |
What
Makes every selector in the thread first-prompt composer keyboard-operable through the app's existing customizable keybindings system, extending the pattern already used by
modelPicker.toggle.modelOptionsPicker.togglemod+shift+eruntimeModePicker.togglemod+shift+aplanMode.togglemod+shift+penvironmentPicker.togglemod+shift+venvModePicker.togglemod+shift+lbranchPicker.togglemod+shift+b(
mod= Ctrl on Linux/Windows, Cmd on macOS.)All six are rebindable in Settings → Keybindings — they flow through the existing command registry, so their labels are derived by
commandLabeland they're upserted into existing user configs by the server's startup sync. No new settings surface was added.Hold-modifier hints
Holding the platform mod key reveals a small
Kbdkeycap on each control, in the disclosure chevron's slot. A keycap and a chevron are within a few pixels of each other, so the row barely moves, the current values (model, effort, access level, Plan/Build) stay readable, and the composer footer and branch toolbar share one treatment.At rest, then with the modifier held:
Dark:
Visibility is computed via
shouldShowCommandHintForModifiers, which deliberately uses subset modifier matching (not the exact-match used by thread jumps) so that holding a bare Ctrl/Cmd reveals the fullmod+shift+*chords.Caps show the whole chord. Apple's glyphs (#4701) are what make that fit:
⌃⇧Esits in a chevron slot whereCtrl+Shift+Eneeded a row of its own.Depends on #4701
The Apple-glyph shortcut labels live in #4701 and are carried here so this branch stands alone. Once #4701 merges, rebasing drops the duplicate.
Run-context behaviour
envModePicker.toggleflips local ↔ worktree directly instead of opening a two-item menu, matching howplanMode.togglealready behaves. Clicking still opens the menu, which is what surfaces the worktree path. On mobile the control lives in the combined run-context sheet, which still opens.Fallbacks
CompactComposerControlsMenu; the Plan/Build toggle still flips directly.MobileRunContextSelectormenu.preventDefault, so the browser default still fires.Tests
Extended keybinding coverage in
packages/contracts,apps/web(mac vs non-mac, subset semantics, customized bindings, no-binding, label resolution, mod-key subtraction, label stability as modifiers go down, glyph output), andapps/serverdefaults enumeration. Typecheck, lint, and theapps/websuite pass (182 files / 1648 tests).🤖 Generated with Claude Code
Note
Medium Risk
Touches global shortcut resolution, label formatting (visible UX change on Linux/Windows), and thread run-context (env/workspace/branch) behavior; mitigated by extensive tests and graceful no-ops when controls are locked.
Overview
Adds six rebindable shortcuts (
mod+shift+e/a/p/v/l/b) for model options, runtime mode, plan/build, environment, workspace mode, and branch pickers, wired through the existing keybindings registry andChatView’s global keydown handler.Composer footer gains mutually exclusive, layout-scoped picker open state (model, traits, runtime mode, compact “more” menu), new
ChatComposerHandletoggles that no-op withoutpreventDefaultwhen unavailable, and hold-modifier hints that swap disclosure chevrons for compact keycaps viashouldShowCommandHintForModifiers(subset modifier matching).Branch toolbar exposes
BranchToolbarHandlefor the same shortcuts: desktop pickers are centrally opened/toggled (one overlay at a time), mobile env/workspace shortcuts open the combined run-context menu, and desktopenvModePicker.toggleflips local ↔ worktree directly instead of opening the two-item menu. Inert environment/workspace indicators get tooltips explaining why they can’t change.Shortcut labeling is unified to Apple-style glyphs on all platforms (
⌃⇧EvsCtrl+Shift+E), with settings chips using sharedformatShortcutTokenLabel.Reviewed by Cursor Bugbot for commit 5751b4b. Bugbot is set up for automated code reviews on this repo. Configure here.
Note
Add keyboard shortcuts to toggle composer and branch toolbar controls with hold-modifier hint badges
modelOptionsPicker.toggle,runtimeModePicker.toggle,planMode.toggle,environmentPicker.toggle,envModePicker.toggle,branchPicker.toggle) with defaultmod+shift+*bindings gated by!terminalFocus.ComposerShortcutKeycap) replace or supplement chevron icons on picker triggers in the composer and branch toolbar.ref-based toggle handles exposed for programmatic control fromChatView.⌃⇧P) on all platforms instead of word-basedCtrl+Shift+Pformat.useLayoutScopedOpenStateto reset picker open state immediately when the rendered layout changes, anduseTerminalFocusto gate shortcuts away from the terminal.formatShortcutLabeloutput changes globally — non-macOS platforms now get glyph labels (e.g.,⌃⇧D) instead ofCtrl+Shift+D, affecting the keybindings settings UI and any other consumers.Macroscope summarized 5751b4b.